/*
 * Copyright (C) 2012 JiangHongTiao
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package sk.lieskove.jianghongtiao.paris.core.classify.old;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import sk.lieskove.jianghongtiao.common.utils.Array;
import sk.lieskove.jianghongtiao.common.utils.PropertiesUtils;
import sk.lieskove.jianghongtiao.websearch.persistence.ClassificationStorage;
import weka.core.Instances;
import weka.core.converters.ArffLoader;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.RemoveByName;
import weka.filters.unsupervised.attribute.StringToWordVector;

/**
 * 
 * @author xjuraj e-mail: jjurco.sk_gmail.com
 */
public class ClassifyManager implements Serializable {
    
    private static transient Logger log = Logger.getLogger(ClassifyManager.class);
    private transient PropertiesUtils pu = new PropertiesUtils(ClassifyManager.class);
    
    /**
     * try to load arff file and in case of error returns <code>null</code>. 
     * otherwise returns instances loaded from the file. 
     * 
     * @param file file to check if format is correct
     * @return returns loaded instances from the file in the case everything goes 
     * well, otherwise returns <code>null</code>.
     */
    public static Instances verifyArffFile(File file){
        BufferedReader reader;
        try {
            reader = new BufferedReader(new FileReader(file));
            ArffLoader.ArffReader arff = new ArffLoader.ArffReader(reader);
            Instances data = arff.getData();
            return data;
        } catch (FileNotFoundException ex) {
            log.warn("File with instances was wrong! File: "+file.getAbsolutePath());
        } catch (IOException ex) {
            log.warn("IO exception while reading arff file. File is wrong! File: "+
                    file.getAbsolutePath());
        }
        return null;
    }
    
    public static List<ClassificationStorage> normalizeToBaseline(int baseline, 
            int max, int count, Map<String, List<ClassificationStorage>> docTypeCI, 
            List<String> docTypeList){
        List<ClassificationStorage> result = new ArrayList<ClassificationStorage>();
        double a = baseline/100.0;
        double b = count-max;
        int maxItems = (int) Math.round((-1.0*a*b)/(a-1.0));
        for (String docType : docTypeList) {
            List<ClassificationStorage> items = docTypeCI.get(docType);
            if(items.size() > maxItems){ 
                result.addAll(Array.randomSubset(items, maxItems));
            } else {
                result.addAll(items);
            }
        }
        return result;
    }
    
    /**
     * convert to the list - guide how to change document type:
     * E.g. string: 'infO,manager;other,Manager' converts to:
     * <ul>
     *   <li>info -&gt; -info-manager-</li>
     *   <li>manager -&gt; -other-manager-</li>
     *   <li>other -&gt; -other-manager-</li>
     * </ul>
     * 
     * in the case the same type is in more join groups, the last one is used
     * @param joinString
     * @return 
     */
    public static Map<String, String> joinItems(String joinString){
        if((joinString == null) || (!joinString.contains(","))){
            return Collections.EMPTY_MAP;
        }
        Map<String, String> result = new HashMap<String, String>();
        for (String joinTypes : joinString.split(";")) {
            String newClass = "-"+joinTypes.replace(',', '-')+"-";
            for (String oldClass : joinTypes.split(",")) {
                result.put(oldClass.toLowerCase(), newClass.toLowerCase());
            }
        }
        return result;
    }
    
    public static Instances modifyInstances(Instances data, int wordsToKeep) {
        StringToWordVector stringToWordVector = new StringToWordVector();
        File sw = new File("/home/xjuraj/Projects/master-thesis/Paris/resources"
                + "/stopwords/inf-man-stop-words.cs");
        RemoveByName removeByName = new RemoveByName();
        if (sw.exists()) {
            stringToWordVector.setStopwords(sw);
        } else {
            log.warn("Stop words not found! Filename: "+sw.getAbsolutePath());
        }
//        stringToWordVector.setIDFTransform(false);
//        stringToWordVector.setTFTransform(false);
//        stringToWordVector.setAttributeIndices("first-last");
//        stringToWordVector.setDoNotOperateOnPerClassBasis(false);
//        stringToWordVector.setInvertSelection(false);
//        stringToWordVector.setLowerCaseTokens(false);
//        stringToWordVector.setMinTermFreq(1);
//        //stringToWordVector.setNormalizeDocLength(new SelectedTag);
//        stringToWordVector.setOutputWordCounts(false);
//        stringToWordVector.setPeriodicPruning(-1.0);
//        stringToWordVector.setUseStoplist(false);
        stringToWordVector.setWordsToKeep(wordsToKeep);
        Instances result = null;
        try {
            stringToWordVector.setInputFormat(data);
            result = Filter.useFilter(data, stringToWordVector);

            removeByName.setExpression("(\\d+)|(.)");
            removeByName.setInvertSelection(false);
            removeByName.setInputFormat(result);
            result = Filter.useFilter(result, removeByName);
        } catch (Exception ex) {
            log.error("Exception thrown while modifying instances with StringToWordVector");
        }

        return result;
    }

}
